﻿#region Using

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Diagnostics.Contracts;
using System.Runtime.Serialization;
using SAPbouiCOM;
using SapFramework.Extension.Interface;
using Form = SapFramework.Interface.Controls.Forms.Base.Form;

#endregion

namespace SapFramework.Interface.Controls.Items.Base
{
    /// <summary>
    /// Classe que realiza um Wrapper para o controle de <see cref="SAPbouiCOM.Items"/> de um formulário (<see cref="SAPbouiCOM.Form"/> do SAP Business One.
    /// 
    /// Seu objetivo é o de agilizar a recuperação de itens provenientes do SAP Business One, 
    /// ao mesmo tempo em que possibilita a criação destes objetos já fazendo sua ligação com o formulário.
    /// </summary>
    public class Items : Dictionary<string, Item>
    {
        /// <summary>
        /// Guarda uma referência para o Form que o originou.
        /// </summary>
        private Form Form { get; set; }

        /// <summary>
        /// Indexador para facilitar acesso 
        /// </summary>
        /// <param name="aKey"></param>
        /// <returns></returns>
        public new dynamic this[ string aKey ]
        {
            get
            {
                if ( ContainsKey( aKey ) )
                    return base[aKey];

                return null;
            }
            set
            {
                Debug.Assert( value.GetType().IsSubclassOf( typeof(Item) ) );

                base[aKey] = value;
            }
        }

        #region Construtores - Passados para internal para que não se possam criar instâncias desta classe fora desta DLL (em especial, da classe Form)

        /// <summary>
        /// Initializes a new instance of the <see cref="T:System.Collections.Generic.Dictionary`2"/> class that is empty, has the default initial capacity, and uses the default equality comparer for the key type.
        /// </summary>
        /// <param name="aForm">Formulário do PadaOne</param>
        internal Items( Form aForm ) : base()
        {
            Contract.Requires( aForm != null );
            Form = aForm;
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="T:System.Collections.Generic.Dictionary`2"/> class that is empty, has the specified initial capacity, and uses the default equality comparer for the key type.
        /// </summary>
        /// <param name="aForm">Formulário do PadaOne</param>
        /// <param name="capacity">The initial number of elements that the <see cref="T:System.Collections.Generic.Dictionary`2"/> can contain.</param><exception cref="T:System.ArgumentOutOfRangeException"><paramref name="capacity"/> is less than 0.</exception>
        internal Items( Form aForm, int capacity ) : base( capacity )
        {
            Contract.Requires( aForm != null );
            Form = aForm;
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="T:System.Collections.Generic.Dictionary`2"/> class that is empty, has the default initial capacity, and uses the specified <see cref="T:System.Collections.Generic.IEqualityComparer`1"/>.
        /// </summary>
        /// <param name="aForm">Formulário do PadaOne</param>
        /// <param name="comparer">The <see cref="T:System.Collections.Generic.IEqualityComparer`1"/> implementation to use when comparing keys, or null to use the default <see cref="T:System.Collections.Generic.EqualityComparer`1"/> for the type of the key.</param>
        internal Items( Form aForm, IEqualityComparer<string> comparer ) : base( comparer )
        {
            Contract.Requires( aForm != null );
            Form = aForm;
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="T:System.Collections.Generic.Dictionary`2"/> class that is empty, has the specified initial capacity, and uses the specified <see cref="T:System.Collections.Generic.IEqualityComparer`1"/>.
        /// </summary>
        /// <param name="aForm">Formulário do PadaOne</param>
        /// <param name="capacity">The initial number of elements that the <see cref="T:System.Collections.Generic.Dictionary`2"/> can contain.</param><param name="comparer">The <see cref="T:System.Collections.Generic.IEqualityComparer`1"/> implementation to use when comparing keys, or null to use the default <see cref="T:System.Collections.Generic.EqualityComparer`1"/> for the type of the key.</param><exception cref="T:System.ArgumentOutOfRangeException"><paramref name="capacity"/> is less than 0.</exception>
        internal Items( Form aForm, int capacity, IEqualityComparer<string> comparer ) : base( capacity, comparer )
        {
            Contract.Requires( aForm != null );
            Form = aForm;
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="T:System.Collections.Generic.Dictionary`2"/> class that contains elements copied from the specified <see cref="T:System.Collections.Generic.IDictionary`2"/> and uses the default equality comparer for the key type.
        /// </summary>
        /// <param name="aForm">Formulário do PadaOne</param>
        /// <param name="dictionary">The <see cref="T:System.Collections.Generic.IDictionary`2"/> whose elements are copied to the new <see cref="T:System.Collections.Generic.Dictionary`2"/>.</param><exception cref="T:System.ArgumentNullException"><paramref name="dictionary"/> is null.</exception><exception cref="T:System.ArgumentException"><paramref name="dictionary"/> contains one or more duplicate keys.</exception>
        internal Items( Form aForm, IDictionary<string, Item> dictionary ) : base( dictionary )
        {
            Contract.Requires( aForm != null );
            Form = aForm;
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="T:System.Collections.Generic.Dictionary`2"/> class that contains elements copied from the specified <see cref="T:System.Collections.Generic.IDictionary`2"/> and uses the specified <see cref="T:System.Collections.Generic.IEqualityComparer`1"/>.
        /// </summary>
        /// <param name="aForm">Formulário do PadaOne</param>
        /// <param name="dictionary">The <see cref="T:System.Collections.Generic.IDictionary`2"/> whose elements are copied to the new <see cref="T:System.Collections.Generic.Dictionary`2"/>.</param><param name="comparer">The <see cref="T:System.Collections.Generic.IEqualityComparer`1"/> implementation to use when comparing keys, or null to use the default <see cref="T:System.Collections.Generic.EqualityComparer`1"/> for the type of the key.</param><exception cref="T:System.ArgumentNullException"><paramref name="dictionary"/> is null.</exception><exception cref="T:System.ArgumentException"><paramref name="dictionary"/> contains one or more duplicate keys.</exception>
        internal Items( Form aForm, IDictionary<string, Item> dictionary, IEqualityComparer<string> comparer ) : base( dictionary, comparer )
        {
            Contract.Requires( aForm != null );
            Form = aForm;
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="T:System.Collections.Generic.Dictionary`2"/> class with serialized data.
        /// </summary>
        /// <param name="aForm">Formulário do PadaOne</param>
        /// <param name="info">A <see cref="T:System.Runtime.Serialization.SerializationInfo"/> object containing the information required to serialize the <see cref="T:System.Collections.Generic.Dictionary`2"/>.</param><param name="context">A <see cref="T:System.Runtime.Serialization.StreamingContext"/> structure containing the source and destination of the serialized stream associated with the <see cref="T:System.Collections.Generic.Dictionary`2"/>.</param>
        internal Items( Form aForm, SerializationInfo info, StreamingContext context ) : base( info, context )
        {
            Contract.Requires( aForm != null );
            Form = aForm;
        }

        #endregion

        /// <summary>
        /// Passa o método Add para protegido, para que este não possa ser usado de fora desta classe.
        /// </summary>
        /// <param name="aKey"></param>
        /// <param name="aValue"></param>
        protected new void Add( string aKey, Item aValue )
        {
            base.Add( aKey, aValue );
        }

        /// <summary>
        /// Adiciona um noto item a coleção. Caso o Item não exista ainda no SAP Business One, ele é criado automáticamente.
        /// </summary>
        /// <param name="aItemUniqueId">Id único do Item, que será usado como chave da coleção</param>
        /// <param name="aItem">Valor que será guardado na coleção, para facilitar a recuperação de referencias, caso necessário</param>
        /// <param name="aItemType">Tipo do item, caso este tenha de ser criado</param>
        /// <returns>Um objeto do tipo SAPbouiCOM.Item, que ja existe ou então será criado no Sap Business One.</returns>
        public SAPbouiCOM.Item Add( string aItemUniqueId, Item aItem, BoFormItemTypes aItemType )
        {
            base.Add( aItemUniqueId, aItem );

            return ( (SAPbouiCOM.Form) Form ).Items.GetItem( aItemUniqueId ) ?? ( ( (IForm) Form ).Items.Add( aItemUniqueId, aItemType ) as SAPbouiCOM.Item );
        }

        /// <summary>
        /// Adiciona um novo item a coleção, ao mesmo tempo em que cria uma nova instancia de sua classe Wrapper.
        /// </summary>
        /// <typeparam name="T">Tipo da classe Wrapper que herda de <see cref="Base.Item"/>.</typeparam>
        /// <param name="aItemUniqueId">Id único do <see cref="Item"/> dentro do SAP Business One.</param>
        /// <returns></returns>
        public T Add<T>( string aItemUniqueId ) where T : Item
        {
            return (T) Activator.CreateInstance( typeof(T), new object[] {Form, aItemUniqueId} );
        }
    }
}